Microprocessors and input/output (I/O) devices often have different operating capabilities relative to their operating frequency. For example, a microprocessor may be capable of transferring data to or from an I/O device at a much faster rate than the I/O device can receive or transmit data. In order not to slow down the microprocessor, RAMs are frequently used as buffers or interface data storage elements between microprocessors and I/O devices. In this manner data can be transferred between the RAM and the microprocessor at one rate and between the RAM and I/O device at another rate.
A typical RAM used as an interface is a first-in first-out (FIFO) buffer in which data bytes are read out in the same order in which they are read into the FIFO. A dual-ported FIFO RAM allows data to be simultaneously read from and written to the buffer. Thus, a fast microprocessor can transfer data into the FIFO at its operating frequency, and a relatively slower I/O device can read the data at its operating frequency. In order to track the location of the next data byte to be read from or written to the FIFO, read and write address pointers are used. The write and read pointers are incremented on each FIFO access, and a byte count for the number of bytes of data in the FIFO is increased or decreased as the amount of data increases or decreases, respectively. The byte count is used by the microprocessor and/or I/O device to indicate when the FIFO should be read and when no more data should be transferred to the FIFO. For example, a fast microprocessor might wait until the FIFO is half full before reading data therefrom. However, no data can be read from an empty FIFO, nor should data be written into a full FIFO.
The read and write address pointers for the FIFO are controlled by the device requesting the read or write function and can therefore operate independently of each other. Independent operation is desirable to allow reading and writing of the FIFO to occur simultaneously, thereby improving the overall system operation. However, truly independent and asynchronous operation presents difficulties in keeping track of the FIFO byte count. For example, asynchronously occurring read and write pulses may operate at different frequencies, they may overlap, and they may have different pulse widths. Asynchronously occurring pulses can also create problems of metastability since the setup and hold times of the pulses are unpredictable.